<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue'
import Recorder from 'recorder-core'
import 'recorder-core/src/engine/mp3'
import 'recorder-core/src/engine/mp3-engine'
import SunComponent from './SunComponent.vue'
import WarnIcon from './icons/WarnIcon.vue'
import LadderIcon from './icons/LadderIcon.vue'
import GeneralButton from './GeneralButton.vue'
import CloudIcon from './icons/CloudIcon.vue'
import showMsg from '@/utils/showMsg'
import { useRoute, useRouter } from 'vue-router'
import axios from 'axios'
import formatDate from '@/utils/formatDate'
import { removeLogin } from '@/utils/auth'
import startAudio from '@/assets/audios/part3-greetings.mp3'
import endAudio from '@/assets/audios/part3-goodbye.mp3'
import BackgroundImage from './BackgroundImage.vue'
import SpeakerIcon from './icons/SpeakerIcon.vue'

const count = defineModel('count', { type: Number })
var recorder = null
const scene = ref('')
const isDerail = ref(false)
const audioUrl = import.meta.env.VITE_PART3_AUDIO_URL || '' // 在线音频获取的 Url
const audioBlob = ref(null)
const audioPath = ref('')
const route = useRoute()
const router = useRouter()
const status = ref('开始') // 开始或者结束
const check = ref(false) // false 未播放 true 播放
const cloudVisible = ref(false)
const container = ref(true)
const control = ref()
const windowCenter = ref()
const nowTrain = ref('train')
const train = ref()
const train2 = ref()
const locomotive = ref()
const locomotive2 = ref()
const fuel = ref()
const wagon = ref()
const tail = ref()
const center = ref()
const position = ref(6.5)
const windowWidth = ref(window.innerWidth)
const animationArea = ref()
const questions = ref([])
const questionStage = ref('locomotive')
const showButtons = ref(false)
const startTime = ref('')
const endTime = ref('')
const dialogueId = ref()
const question = ref([])
// 车厢部分
// locomotive 火车头
// fuel 燃油车厢
// wagon 火车车厢
// converter 转换器
// tail 火车尾
// end 结束
let intervalId = null

const speak = (t) => {
  // text 为数组
  console.log(t)
  const text = t.filter((t) => !t.startsWith('儿童'))
  console.log(`${audioUrl}/adult/${text}.mp3`)
  let currentAudioIndex = 0
  let audio = new Audio(`${audioUrl}/adult/${text[currentAudioIndex]}.mp3`)
  console.log(`${audioUrl}/adult/${text[currentAudioIndex]}.mp3`)
  audio.addEventListener('ended', onAudioEnded)
  function playAudio() {
    audio.play()
  }
  function onAudioEnded() {
    currentAudioIndex++
    if (currentAudioIndex < text.length) {
      audio.src = `${audioUrl}/adult/${text[currentAudioIndex]}.mp3`
      audio.play()
    } else if (currentAudioIndex === text.length) {
      console.log('所有音频播放结束')
      console.log('questionStage', questionStage.value)
      if (questionStage.value === 'locomotive' && route.query.difficulty === '0') {
        // 播放开始提示
        audio.src = startAudio
        audio.play()
      }
    }
  }
  // 开始播放
  playAudio()
}

const speakEnd = (t) => {
  // text 为数组
  console.log(t)
  const text = t.filter((t) => !t.startsWith('儿童'))
  console.log(`${audioUrl}/adult/${text}.mp3`)
  let currentAudioIndex = 0
  let audio = new Audio(`${audioUrl}/adult/${text[currentAudioIndex]}.mp3`)
  console.log(`${audioUrl}/adult/${text[currentAudioIndex]}.mp3`)
  audio.addEventListener('ended', onAudioEnded)
  function playAudio() {
    audio.play()
  }
  function onAudioEnded() {
    currentAudioIndex++
    if (currentAudioIndex < text.length) {
      audio.src = `${audioUrl}/adult/${text[currentAudioIndex]}.mp3`
      audio.play()
    } else if (currentAudioIndex === text.length) {
      console.log('所有音频播放结束')
      console.log('questionStage', questionStage.value)
      if (route.query.difficulty === '0') {
        // 播放结束提示
        console.log('end-----------')
        audio.src = endAudio
        audio.play()
      }
    }
  }
  // 开始播放
  playAudio()
}

const speakChild = (t) => {
  let text = t.replace(/^儿童：/, '')
  text = `${audioUrl}/boy/${text}.mp3`
  console.log(text)
  const audio = new Audio(text)
  audio.play()
}

const fetchNewQuestions = async () => {
  try {
    const response = await axios.get('/api/north/stem/ques/p3', {
      headers: {
        Authorization: localStorage.getItem('token')
      },
      params: {
        difficulty: route.query.difficulty
      }
    })
    console.log(response)
    const { code } = response.data
    if (code === 401) {
      showMsg({
        type: 'error',
        msg: '登录过期，请重新登录',
        duration: 1000,
        onClose: () => {
          removeLogin()
          router.push({ name: 'login' })
        }
      })
    } else if (code === 200) {
      const { data } = response.data
      console.log(data)
      if (!data) {
        showMsg({
          type: 'error',
          msg: `今天的 PART3 ${route.query.difficulty === '0' ? '简单' : '困难'}已经完成啦，小朋友明天再来吧`,
          duration: 1000,
          onClose: () => {
            router.push({ name: 'game-select' })
          }
        })
      } else {
        startTime.value = formatDate(new Date())
        console.log(startTime.value)
        dialogueId.value = data.dialogueId
        console.log('dialogueId', dialogueId.value)
        questions.value = data.ques.map((item) => {
          return item
            .replace(/程序：/g, '')
            .replace(/\?/g, '？')
            .replace(/!/g, '！')
            .split('\n')
          // .filter((t) => !t.startsWith('儿童'))
        })
        scene.value = data.scene.slice(0, -2)
        console.log(questions.value)
      }
    } else throw new Error()
  } catch (e) {
    console.log(e)
    showMsg({
      type: 'error',
      msg: '网络错误，请稍后重试',
      duration: 1000,
      onClose: () => {
        router.push({ name: 'game-select' })
      }
    })
  }
}

const updateWidth = () => {
  windowWidth.value = window.innerWidth
}

const handleStop = (el) => {
  if (nowTrain.value === 'train') {
    train.value.style.animationPlayState = 'paused'
  } else {
    train2.value.getAnimations()[0].pause()
  }
  showButtons.value = true
  cloudVisible.value = true

  if (questionStage.value === 'locomotive') {
    position.value = 6.5
    question.value = questions.value[0]
  } else if (questionStage.value === 'fuel') {
    position.value = 18.5
    question.value = questions.value[1]
  } else if (questionStage.value === 'wagon') {
    position.value = 29
    question.value = questions.value[2]
  } else if (questionStage.value === 'converter') {
    position.value = -6
    question.value = questions.value[3]
  } else if (questionStage.value === 'tail') {
    position.value = 29
    question.value = questions.value[4]
  }
  question.value = question.value.filter((element) => element !== '')
  if (!check.value) {
    // 播放
    if (questionStage.value === 'tail') speakEnd(question.value)
    else speak(question.value)
    check.value = !check.value
  }
  if (el) {
    el.classList.add('inner-shadow')
  }
}

const handleStart = () => {
  if (nowTrain.value === 'train') {
    train.value.style.animationPlayState = 'running'
  } else {
    train2.value.getAnimations()[0].play()
  }
  showButtons.value = false
  cloudVisible.value = false
  check.value = false
  if (locomotive.value) {
    locomotive.value.classList.remove('inner-shadow')
  }
  if (fuel.value) {
    fuel.value.classList.remove('inner-shadow')
  }
  if (wagon.value) {
    wagon.value.classList.remove('inner-shadow')
  }
  if (tail.value) {
    tail.value.classList.remove('inner-shadow')
  }
}

const checkPosition = () => {
  if (!locomotive.value || !fuel.value) return
  const screenCenter = windowWidth.value / 2
  let el
  if (questionStage.value === 'locomotive') {
    center.value = locomotive.value.getBoundingClientRect().left + locomotive.value.offsetWidth / 2
    el = locomotive.value
  } else if (questionStage.value === 'fuel') {
    center.value = fuel.value.getBoundingClientRect().left + fuel.value.offsetWidth / 2
    el = fuel.value
  } else if (questionStage.value === 'wagon') {
    center.value = wagon.value.getBoundingClientRect().left + wagon.value.offsetWidth / 2
    el = wagon.value
  } else if (questionStage.value === 'converter') {
    center.value = locomotive2.value.getBoundingClientRect().left + locomotive.value.offsetWidth
  } else if (questionStage.value === 'tail') {
    center.value = tail.value.getBoundingClientRect().left + tail.value.offsetWidth / 2
    el = tail.value
  }
  if (Math.abs(center.value - screenCenter) < 5 && questionStage.value !== 'end') {
    handleStop(el)
  }
  if (questionStage.value === 'converter' && train.value.getBoundingClientRect().right < 0) {
    control.value.checked = false
    train.value.style.display = 'none'
    nowTrain.value = 'train2'
    train2.value.getAnimations()[0].play()
  }
  if (questionStage.value === 'end' && train.value.getBoundingClientRect().right < 0) {
    train.value.style.display = 'none'
  }
}

const updatePosition = () => {
  checkPosition()
  requestAnimationFrame(updatePosition)
}

const handleVisibilityChange = () => {
  if (document.visibilityState === 'hidden') {
    handleStop()
  } else if (document.visibilityState === 'visible') {
    handleStart()
  }
}

const checkRecorder = () => {
  recorder = new Recorder({ type: 'mp3' })
  recorder.open(
    () => {
      console.log('已打开录音')
    },
    (msg, isUserNotAllow) => {
      //用户拒绝未授权或不支持
      console.log((isUserNotAllow ? 'UserNotAllow，' : '') + '无法录音:' + msg)
      showMsg({
        type: 'error',
        msg: '请先打开录音权限再进入 PART3',
        duration: 1000,
        onClose: () => {
          router.push({ name: 'game-select' })
        }
      })
    }
  )
}

const startRecord = () => {
  console.warn('-----------')
  console.log(recorder)
  recorder.start()
  console.warn('-----------')
}

const stopRecord = () => {
  recorder.stop(
    function (blob, duration) {
      console.log(blob, '时长:' + duration + 'ms')
      audioBlob.value = blob
      // 将 blob 下载到本地
      // 将音频文件下载到本地
      // const url = URL.createObjectURL(blob)
      // const a = document.createElement('a')
      // a.href = url
      // a.download = 'audio.mp3'
      // a.click()
    },
    function (msg) {
      console.log('录音失败:' + msg)
      showMsg({
        type: 'error',
        msg: '请先打开录音权限再进入 PART3',
        duration: 1000,
        onClose: () => {
          router.push({ name: 'game-select' })
        }
      })
    }
  )
}

const record = () => {
  if (isDerail.value) return showMsg({ type: 'error', msg: '请先让火车回到正确的轨道上吧！' })
  if (status.value === '开始') {
    status.value = '结束'
    startRecord()
  } else {
    status.value = '开始'
    stopRecord()
  }
}

const uploadRecord = async () => {
  endTime.value = formatDate(new Date())
  try {
    const response = await axios.post(
      '/api/north/part/three',
      {
        path: audioPath.value,
        ques: question.value.join(''),
        difficulty: parseInt(route.query.difficulty),
        dialogueId: parseInt(dialogueId.value),
        beginTime: startTime.value,
        endTime: endTime.value
      },
      {
        headers: {
          Authorization: localStorage.getItem('token')
        }
      }
    )
    const { code } = response.data
    if (code === 401) {
      showMsg({
        type: 'error',
        msg: '登录过期，请重新登录',
        duration: 1000,
        onClose: () => {
          removeLogin()
          router.push({ name: 'login' })
        }
      })
    } else if (code === 200) {
      console.log('上传成功')
      console.log(response.data)
      audioBlob.value = null
    } else {
      throw new Error()
    }
  } catch (e) {
    console.log(e)
    showMsg({
      type: 'error',
      msg: '网络错误，请稍后重试',
      duration: 1000,
      onClose: () => {
        router.push({ name: 'game-select' })
      }
    })
  }
}

const uploadAudio = async () => {
  const formData = new FormData()
  formData.append('file', audioBlob.value, 'audio.mp3')
  try {
    const response = await axios.post('/api/north/upload', formData, {
      headers: {
        Authorization: localStorage.getItem('token')
      }
    })
    console.log(response)
    console.log(response.data)
    const { code } = response.data
    if (code === 401) {
      showMsg({
        type: 'error',
        msg: '登录过期，请重新登录',
        duration: 1000,
        onClose: () => {
          removeLogin()
          router.push({ name: 'login' })
        }
      })
    } else if (code === 200) {
      console.log('上传成功')
      audioPath.value = response.data.fileName
      console.log('audioPath', audioPath.value)
      await uploadRecord()
    } else {
      throw new Error()
    }
  } catch (e) {
    console.log(e)
  }
}

// 在轨
const onTrack = async () => {
  if (isDerail.value) {
    isDerail.value = false
    if (nowTrain.value === 'train') {
      train.value.style.bottom = 'calc(50% + 2.6rem)'
    } else {
      train2.value.style.bottom = 'calc(50% + 2.6rem)'
    }
  } else {
    if (!audioBlob.value) return showMsg({ type: 'error', msg: '请先录音' })
    await uploadAudio()
  }
  if (questionStage.value === 'locomotive') {
    questionStage.value = 'fuel'
  } else if (questionStage.value === 'fuel') {
    questionStage.value = 'wagon'
  } else if (questionStage.value === 'wagon') {
    questionStage.value = 'converter'
  } else if (questionStage.value === 'converter') {
    questionStage.value = 'tail'
  } else if (questionStage.value === 'tail') {
    questionStage.value = 'end'
  }
}

// 脱轨
const derail = async () => {
  if (!audioBlob.value) return showMsg({ type: 'error', msg: '请先录音' })
  await uploadAudio()
  isDerail.value = true
  if (nowTrain.value === 'train') {
    train.value.style.bottom = 'calc(50% + 2.6rem - 100px)'
  } else {
    train2.value.style.bottom = 'calc(50% + 2.6rem - 100px)'
  }
}

watch(questionStage, (newVal, oldVal) => {
  console.log('questionStage', newVal, oldVal)
  handleStart()
})

const next = () => {
  count.value++
}

const finish = () => {
  router.push({ name: 'game-select' })
}

onMounted(async () => {
  const difficulty = route.query.difficulty
  if (difficulty !== '0' && difficulty !== '2') {
    router.push({ name: 'game-select' })
  }
  checkRecorder()
  await fetchNewQuestions()
  control.value.checked = true
  train2.value.getAnimations()[0].pause()
  window.addEventListener('resize', updateWidth)
  document.addEventListener('visibilitychange', handleVisibilityChange)
  requestAnimationFrame(updatePosition)
  intervalId = setInterval(checkPosition, 100)
})

onUnmounted(() => {
  window.removeEventListener('resize', updateWidth)
  document.removeEventListener('visibilitychange', handleVisibilityChange)
  if (intervalId) {
    clearInterval(intervalId)
  }
  if (!recorder) {
    recorder.close()
  }
})
</script>

<template>
  <div class="container" v-if="container">
    <background-image />
    <sun-component class="sun" style="z-index: 100" />
    <general-button
      style="z-index: 101; position: absolute; left: 5%; top: 5%"
      v-if="questionStage === 'end'"
      @click="finish"
      >结束对话</general-button
    >
    <general-button
      style="z-index: 101; position: absolute; right: 5%; top: 5%"
      v-if="questionStage === 'end'"
      @click="next"
      >下段对话</general-button
    >
    <div
      style="
        z-index: 101;
        position: absolute;
        bottom: 5%;
        left: 50%;
        transform: translate(-50%, -50%);
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
      "
    >
      <div
        style="display: flex; flex-direction: column; align-items: center; justify-content: center"
      >
        <div
          v-if="
            cloudVisible &&
            questionStage !== 'locomotive' &&
            questionStage !== 'tail' &&
            route.query.difficulty === '0'
          "
          class="base-border"
          style="margin-bottom: 8px; display: flex; align-items: center; justify-content: center"
        >
          <span style="font-size: 32px">{{
            question[question.length - 1].replace(/^儿童/, '你')
          }}</span>
          <speaker-icon :size="28" @click="speakChild(question[question.length - 1])" />
        </div>
        <general-button @click="record" v-if="showButtons" style="width: fit-content"
          >{{ status }}录音</general-button
        >
      </div>
    </div>
    <general-button
      style="z-index: 101; position: absolute; bottom: 5%; left: 5%"
      @click="onTrack"
      v-if="showButtons"
      >在轨</general-button
    >
    <general-button
      style="z-index: 101; position: absolute; bottom: 5%; right: 5%"
      @click="derail"
      v-if="showButtons"
      >脱轨</general-button
    >
    <div class="animation-area" ref="animationArea">
      <div class="center" ref="windowCenter">
        <div
          style="
            position: absolute;
            top: 0;
            width: 18%;
            height: calc(50vh - 2.6rem);
            background: linear-gradient(#79bcff, #acd7ff 100%);
            z-index: 2;
          "
        ></div>
        <div class="train" ref="train" style="z-index: 1">
          <cloud-icon
            v-show="cloudVisible"
            :style="{
              position: 'absolute',
              bottom: '11rem',
              left: `${position}rem`,
              // 车头 6.5rem
              // 燃油车厢 18.5rem
              // 货车车厢 29rem
              // 转换器 6.5rem
              // 车尾 39rem
              transform: 'scaleX(-1) translate(50%)'
            }"
            @click="speak(question)"
            :content="question"
          ></cloud-icon>
          <div
            class="engine-front"
            ref="locomotive"
            style="display: flex; align-items: center; justify-content: center"
          >
            <div class="chimney">
              <div class="smoke"></div>
              <div class="smoke smoke-2"></div>
              <div class="smoke smoke-3"></div>
              <div class="smoke smoke-4"></div>
            </div>
            <span style="transform: scaleX(-1); font-size: 34px; color: white">{{ scene }}</span>
          </div>
          <div class="engine-body"></div>
          <div class="compartment fuel-compartment" ref="fuel">
            <warn-icon :size="48" />
            <ladder-icon :size="60" />
          </div>
          <div class="compartment wagon-compartment" ref="wagon">
            <div class="compartment-window"></div>
          </div>
          <div class="compartment tail-compartment">
            <div class="compartment-no-window"></div>
            <div class="tail"></div>
          </div>
          <div class="wheel-holder">
            <div class="wheel"></div>
            <div class="wheel wheel-2">
              <div class="wheel-joint"></div>
              <div class="wheel-joint wheel-joint-2"></div>
            </div>
            <div class="wheel wheel-3"></div>
            <div class="wheel wheel-4"></div>
            <div class="wheel wheel-5"></div>
            <div class="wheel wheel-6"></div>
            <div class="wheel wheel-7"></div>
            <div class="wheel wheel-8"></div>
            <div class="wheel wheel-9"></div>
          </div>
        </div>
        <label
          class="switch"
          style="position: absolute; bottom: calc(50vh + 3.1rem); right: 70%; z-index: 1"
        >
          <input type="checkbox" ref="control" />
          <span class="toggle"></span>
        </label>
        <div class="bridge" style="z-index: 0"></div>
        <div
          style="
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: calc(50vh - 2.6rem);
            background: linear-gradient(#79bcff, #acd7ff 100%);
          "
        ></div>
        <div
          style="
            position: relative;
            top: calc(50% + 2.6rem);
            right: 80vw;
            transform: rotate(45deg) scaleX(-1);
            width: 200vw;
            z-index: 1;
          "
        >
          <div class="train-2" ref="train2" style="z-index: 1">
            <cloud-icon
              v-show="cloudVisible"
              :style="{
                position: 'absolute',
                bottom: '18rem',
                left: `${position}rem`,
                // 车头 6.5rem
                // 燃油车厢 18.5rem
                // 货车车厢 29rem
                // 转换器 6.5rem
                // 车尾 39rem
                transform: 'rotate(45deg) translate(50%)'
              }"
              @click="speak(question)"
              :content="question"
            ></cloud-icon>
            <div
              class="engine-front"
              ref="locomotive2"
              style="display: flex; align-items: center; justify-content: center"
            >
              <div class="chimney">
                <div class="smoke"></div>
                <div class="smoke smoke-2"></div>
                <div class="smoke smoke-3"></div>
                <div class="smoke smoke-4"></div>
              </div>
              <span style="font-size: 34px; color: white">{{ scene }}</span>
            </div>
            <div class="engine-body"></div>
            <div class="compartment fuel-compartment">
              <warn-icon :size="48" />
              <ladder-icon :size="60" />
            </div>
            <div class="compartment wagon-compartment">
              <div class="compartment-window"></div>
            </div>
            <div class="compartment tail-compartment" ref="tail">
              <div class="compartment-no-window"></div>
              <div class="tail"></div>
            </div>
            <div class="wheel-holder">
              <div class="wheel"></div>
              <div class="wheel wheel-2">
                <div class="wheel-joint"></div>
                <div class="wheel-joint wheel-joint-2"></div>
              </div>
              <div class="wheel wheel-3"></div>
              <div class="wheel wheel-4"></div>
              <div class="wheel wheel-5"></div>
              <div class="wheel wheel-6"></div>
              <div class="wheel wheel-7"></div>
              <div class="wheel wheel-8"></div>
              <div class="wheel wheel-9"></div>
            </div>
          </div>
          <div class="bridge" style="z-index: 0"></div>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
@import '@/styles/train.css';

.sun {
  position: absolute;
  top: 10%;
  left: 20%;
}

.inner-shadow {
  position: absolute;
  z-index: 0;
  background-color: #ccc;
  display: flex;
  justify-content: center;
  align-items: center;
  box-shadow: 0 0 20px 10px rgba(255, 255, 255, 0.5);
  box-shadow:
    0 0 80px 40px rgba(255, 255, 0, 0.5),
    0 0 160px 80px rgba(255, 255, 0, 0.3),
    0 0 240px 120px rgba(255, 255, 0, 0.1);
}

@keyframes rotate45 {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(45deg);
  }
}

/* The switch - the box around the slider */
.switch {
  font-size: 17px;
  position: relative;
  display: inline-block;
  width: 3.5em;
  height: 2em;
}

/* Hide default HTML checkbox */
.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

.toggle {
  position: relative;
  display: flex;
  width: 3.8em;
  height: 1em;
  background-color: rgb(165, 165, 165);
  justify-content: center;
}

.toggle::before {
  content: '';
  position: absolute;
  z-index: -1;
  width: 1em;
  height: 3em;
  margin-bottom: 0.5em;
  bottom: 0;
  background-color: rgb(153, 104, 39);
  box-shadow: 0 -1em 0 0 rgb(165, 165, 165);
  transform-origin: bottom;
  transform: rotateZ(-30deg);
  transition: transform 150ms;
}

.switch input:checked + .toggle::before {
  transform: rotateZ(30deg);
}

.switch input:checked + .toggle {
  box-shadow: 0 -1em 2em 0 rgb(230, 111, 111);
}

.base-border {
  background-color: #ffe2b3;
  border: 6px solid #f55a36;
  font-size: 28px;
  border-radius: 20px;
}
</style>
